﻿using NICWebApi.Extensions.RESTfulResult.Internal;

/// <summary>
/// 统一上下文
/// </summary>
public static class UnifyContext
{
    /// <summary>
    /// 返回RESTful结果
    /// </summary>
    /// <param name="statusCode">HTTP状态码</param>
    /// <param name="succeeded">操作是否成功，默认值为false</param>
    /// <param name="data">返回的数据，默认值为null</param>
    /// <param name="errors">错误信息，默认值为null</param>
    /// <returns>RESTful结果对象</returns>
    public static RESTfulResult<object> RESTfulResult(int statusCode, bool succeeded = false, object data = null, object errors = null)
    {
        // 只要不是实体类型，都进行字段名驼峰转换
        if (data != null && !IsEntityType(data))
        {
            data = ConvertDynamicKeysToCamelCase(data);
        }

        return new RESTfulResult<object>
        {
            StatusCode = statusCode, // 设置HTTP状态码
            Succeeded = succeeded, // 设置操作是否成功
            Data = data, // 设置返回的数据
            Errors = errors, // 设置错误信息
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() // 设置当前时间戳（Unix时间）
        };
    }

    /// <summary>
    /// 判断是否为实体类型（有属性的自定义class/record）
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    private static bool IsEntityType(object obj)
    {
        if (obj == null) return false;
        var type = obj.GetType();
        if (type == typeof(string) || type.IsPrimitive || type.IsEnum)
            return false;
        if (typeof(System.Collections.IDictionary).IsAssignableFrom(type))
            return false;
        if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string))
            return false;
        if (type.FullName != null && (type.FullName.StartsWith("System.Dynamic") || type.FullName.Contains("AnonymousType")))
            return false;
        // 有属性的自定义类型视为实体
        return type.IsClass && type.GetProperties().Length > 0 && (type.Namespace == null || !type.Namespace.StartsWith("System"));
    }

    /// <summary>
    /// 递归转换所有非实体类型的key为驼峰
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    private static object ConvertDynamicKeysToCamelCase(object data)
    {
        if (data == null) return null;
        if (data is IDictionary<string, object> dict)
        {
            var result = new Dictionary<string, object>();
            foreach (var kv in dict)
            {
                var key = kv.Key.ConvertToCamelCase();
                result[key] = ConvertDynamicKeysToCamelCase(kv.Value);
            }
            return result;
        }
        if (data is System.Collections.IEnumerable enumerable && !(data is string))
        {
            var list = new List<object>();
            foreach (var item in enumerable)
            {
                list.Add(ConvertDynamicKeysToCamelCase(item));
            }
            return list;
        }
        // 处理ExpandoObject
        if (data is System.Dynamic.ExpandoObject expando)
        {
            var dictExpando = (IDictionary<string, object>)expando;
            var result = new Dictionary<string, object>();
            foreach (var kv in dictExpando)
            {
                var key = kv.Key.ConvertToCamelCase();
                result[key] = ConvertDynamicKeysToCamelCase(kv.Value);
            }
            return result;
        }
        // 处理匿名对象
        var type = data.GetType();
        if (type.FullName != null && type.FullName.Contains("AnonymousType"))
        {
            var result = new Dictionary<string, object>();
            foreach (var prop in type.GetProperties())
            {
                var key = prop.Name.ConvertToCamelCase();
                var value = prop.GetValue(data);
                result[key] = ConvertDynamicKeysToCamelCase(value);
            }
            return result;
        }
        // 其他类型直接返回
        return data;
    }

    /// <summary>
    /// 检查是否是有效的结果（可进行规范化的结果）
    /// </summary>
    /// <param name="result">Action结果对象</param>
    /// <param name="data">输出参数，用于返回有效数据</param>
    /// <returns>是否是有效的结果</returns>
    public static bool CheckVaildResult(IActionResult result, out object data)
    {
        data = null; // 初始化输出参数

        // 排除以下结果，跳过规范化处理
        var isDataResult = result switch
        {
            ViewResult => false, // 视图结果
            PartialViewResult => false, // 部分视图结果
            FileResult => false, // 文件结果
            ChallengeResult => false, // 挑战结果
            SignInResult => false, // 登录结果
            SignOutResult => false, // 登出结果
            RedirectToPageResult => false, // 重定向到页面结果
            RedirectToRouteResult => false, // 重定向到路由结果
            RedirectResult => false, // 重定向结果
            RedirectToActionResult => false, // 重定向到Action结果
            LocalRedirectResult => false, // 本地重定向结果
            ForbidResult => false, // 禁止结果
            ViewComponentResult => false, // 视图组件结果
            PageResult => false, // 页面结果
            NotFoundResult => false, // 未找到结果
            NotFoundObjectResult => false, // 未找到对象结果
            _ => true, // 其他类型结果视为有效结果
        };

        // 目前支持返回值 ActionResult
        if (isDataResult) data = result switch
        {
            // 处理内容结果
            ContentResult content => content.Content,
            // 处理对象结果
            ObjectResult obj => obj.Value,
            // 处理 JSON 对象
            JsonResult json => json.Value,
            _ => null, // 其他类型结果返回null
        };

        return isDataResult; // 返回是否是有效结果
    }

    /// <summary>
    /// 转换为驼峰命名
    /// </summary>
    internal static string ConvertToCamelCase(this string str)
    {
        if (string.IsNullOrEmpty(str) || char.IsLower(str[0]))
            return str;
        return char.ToLowerInvariant(str[0]) + str.Substring(1);
    }
}